package com.owc.service.impl.app;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.owc.common.enums.ExceptionEnum;
import com.owc.common.enums.ExchangeType;
import com.owc.common.exception.BadRequestException;
import com.owc.common.lock.Lock;
import com.owc.common.Const.LockConst;
import com.owc.common.lock.ULock;
import com.owc.dao.ExchangeMapper;
import com.owc.domain.PageBean;
import com.owc.domain.dto.BalanceDTO;
import com.owc.domain.dto.ExchangeBaseDTO;
import com.owc.domain.dto.admin.RateConfigDTO;
import com.owc.domain.dto.admin.SystemConfigDTO;
import com.owc.domain.entity.Exchange;
import com.owc.domain.entity.Token;
import com.owc.domain.vo.admin.ExchangeQueryVo;
import com.owc.domain.vo.app.ExchangeVo;
import com.owc.filter.content.SecurityContextHolder;
import com.owc.service.admin.SystemService;
import com.owc.service.app.ExchangeService;
import com.owc.service.app.WalletService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

/**
 * @Author xiaom
 * @Date 2020/2/27 14:11
 * @Version 1.0.0
 * @Description <>
 **/
@Service
@Slf4j
public class ExchangeServiceImpl implements ExchangeService {

    @Autowired
    private SystemService systemService;
    @Autowired
    private WalletService walletService;
    @Autowired
    private TransactionService transactionService;
    @Resource
    private ExchangeMapper exchangeMapper;

    @Override
    public List<RateConfigDTO> getRateConfig() {
        SystemConfigDTO.ExchangeBean bean = systemService.getSystemConfig().getExchangeBean();
        if(bean == null){
            throw new BadRequestException("Not found rate config.");
        }

        List<RateConfigDTO> rateConfigs = new ArrayList<>();

        bean.getRateMap().keySet().forEach(key -> {
            ExchangeType.match(key).ifPresent(type -> {
                RateConfigDTO dto = new RateConfigDTO();
                dto.setConfigKey(key);
                dto.setRate(bean.getRateMap().get(key));
                dto.setConfigName(type.getMapper().getFrom() + "兑换" + type.getMapper().getTo() + ",汇率" + dto.getRate());
                dto.setTokenId(walletService.getTokenByName(type.getMapper().getFrom()).getId());
                dto.setTokenName(type.getMapper().getFrom());
                dto.setToTokenName(type.getMapper().getTo());
                rateConfigs.add(dto);
            });
        });
        return rateConfigs;
    }

    @Override
    @ULock
    public Boolean exchange(ExchangeVo exchangeVo) throws Exception {
        try {
            //检查参数合法性,并返回TokenType
            ExchangeType type = frontValidParams(exchangeVo);
            //发起兑换
            transactionService.executeExchange(exchangeVo,type);
        }catch (Exception e){
            log.error("兑换出现异常 exMsg:{}",e.getMessage());
            throw e;
        }
        return true;
    }

    @Override
    public PageBean<ExchangeBaseDTO> getExchangeRecord(Integer pageIndex, Integer pageSize) {
        PageHelper.startPage(pageIndex,pageSize);

        List<ExchangeBaseDTO> list = exchangeMapper.selectByUserId(SecurityContextHolder.getCurrentUserId());
        PageInfo<ExchangeBaseDTO> pageInfo = new PageInfo<>(list);
        return PageBean.pageBean(pageInfo.getTotal(),list);
    }

    @Override
    public PageInfo<Exchange> getExchangeOrderList(ExchangeQueryVo queryVo) {
        PageHelper.startPage(queryVo.getPageIndex(),queryVo.getPageSize());
        List<Exchange> list = exchangeMapper.selectAllByFilter(queryVo);
        return new PageInfo<>(list);
    }

    private ExchangeType frontValidParams(ExchangeVo exchangeVo){
        Optional<ExchangeType> exchangeType = ExchangeType.match(exchangeVo.getType());

        if(!exchangeType.isPresent()){
            log.error("异常的兑换选择 type:[{}]",exchangeVo.getType());
            throw new BadRequestException("Abnormal choice");
        }
        if(exchangeVo.getAmount().compareTo(BigDecimal.ZERO) < 0){
            throw new BadRequestException("Exchange amount must cannot be negative");
        }

        //检查汇率是否一致
        BigDecimal rate = systemService.getSystemConfig().getExchangeBean().getRateMap().get(exchangeType.get().getType());
        if(rate.compareTo(exchangeVo.getRate()) != 0){
            log.error("兑换失败,数据库汇率:[{}] 当前传递汇率:[{}]",rate,exchangeVo.getRate());
            throw new BadRequestException(ExceptionEnum.RATE_CHANGE);
        }
        //识别兑换类型
        ExchangeType.Mapper mapper = exchangeType.get().getMapper();

        //根据tokenName获取token信息
        Token fromToken = walletService.getTokenByName(mapper.getFrom());
        Token toToken = walletService.getTokenByName(mapper.getTo());
        if(fromToken == null || toToken == null){
            throw new BadRequestException(ExceptionEnum.INVALID_TOKEN_ERR);
        }

        //判断余额是否充足
        BalanceDTO balanceDTO = walletService.getTokenBalance(fromToken.getId());
        if(balanceDTO.getBalance().compareTo(exchangeVo.getAmount()) < 0){
            log.error("发起兑换失败. 兑换金额:[{}] 账户余额:[{}] 代币类型:[{}]",exchangeVo.getAmount(),balanceDTO.getBalance(),balanceDTO.getTokenName());
            throw new BadRequestException(ExceptionEnum.BALANCE_BELOW_ERR);
        }

        return exchangeType.get();
    }

}
